/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frsutl.c                                           */
/*  NOTE      =                                                    */
/*  DATE      = 2014/11/10 by yaohl                                */
/*******************************************************************/
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <uuid/uuid.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>

#include "frcomm.h"
#include "frmem.h"
#include "frlog.h"

/*******************************************************************************
*  FUNC     :  生成uuid,
*  ARGS     :  p_uuid    (生成uuid数据)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  数据空间长度必须>=37
*******************************************************************************/
int fruuid(char *p_uuid)
{
    uuid_t uuid;

    if(p_uuid == NULL)
    	return FR_FAIL;

    uuid_generate_time(uuid);
    uuid_unparse(uuid, p_uuid);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  字符串ip转换成数字ip
*  ARGS     :  dotted    (字符串形式的ip)
*  RTN      :  数字的ip
*  NOTE     :  转换不了时返回0
*******************************************************************************/
u_int iptools_parse_ipaddr(const char *dotted)
{
    struct in_addr addr;
    unsigned char *addrp;
    unsigned int onebyte;
    char buf[20], *p, *q;
    int i;

    if (dotted == NULL)
        return 0;

    /* copy dotted string, because we need to modify it */
    strncpy(buf, dotted, sizeof(buf) - 1);
    buf[sizeof(buf) - 1] = '\0';
    addrp = (void *)&addr.s_addr;

    p = buf;
    for (i = 0; i < 3; ++i) {
        if ((q = strchr(p, '.')) == NULL) {
            /* autocomplete, this is a network address */
            onebyte = atoi(p);
            addrp[i] = onebyte;
            while (i < 3)
                addrp[++i] = 0;

            return addr.s_addr;
        }

        *q = '\0';
        onebyte = atoi(p);
        addrp[i] = onebyte;
        p = q + 1;
    }

    /* we have checked 3 bytes, now we check the last one */
    onebyte = atoi(p);
    addrp[3] = onebyte;
    return addr.s_addr;
}

/*******************************************************************************
*  FUNC     :  字符串ip段转换成起始ip和结束ip
*  ARGS     :  dotted    (字符串形式的ip段)
*           :  min_ip    (起始ip地址)
*           :  max_ip    (结束ip地址)
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
void iptools_parse_iprange(char* dotted, u_int* min_ip, u_int* max_ip)
{
    char *token, *cur = dotted;
    char arr_min_ip[20];
    *min_ip = 0;
    *max_ip = 0;
    
    if(dotted == NULL || dotted[0]=='\0') return;

    token = strchr(cur, '-');
    if (token==NULL)
    {
        *min_ip = iptools_parse_ipaddr(cur);
        *max_ip = *min_ip;
        return;
    }
    
    snprintf(arr_min_ip, token - cur + 1, "%s", cur);
    *min_ip = iptools_parse_ipaddr(arr_min_ip);
    *max_ip = iptools_parse_ipaddr(token + 1);
}

/*******************************************************************************
*  FUNC     :  端口段转换成起始端口和结束端口
*  ARGS     :  dotted     (字符串形式的端口段)
*           :  sport      (起始端口)
*           :  dport      (结束端口)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void iptools_parse_portrange(char* dotted, u_short* sport, u_short* dport)
{
    char *token, *cur = dotted;
    *sport = 0;
    *dport = 0;

    if(dotted == NULL || dotted[0]=='\0') return;

    token = strchr(cur, '-');
    if (token==NULL)
    {
        *sport = atoi(cur);
        *dport = *sport;
        return;
    }
    
    *sport = atoi(cur);
    *dport = atoi(token + 1);
}

/*******************************************************************************
*  FUNC     :  字符串mac地址转换成标准内存
*  ARGS     :  str_mac    (字符串形式的mac)
*           :  mac        (标准形式mac地址)
*           :  size       (标准形式mac地址的长度)
*  RTN      :  0  失败
*           :  1  成功
*  NOTE     :  转换不了时返回0
*******************************************************************************/
int iptools_parse_mac(char* str_mac, unsigned char* mac, int size)
{
    unsigned int i;
    char *end;
    
    if(size!=APM_MAC_SIZE || str_mac == NULL || mac == NULL)
        return 0;

    for (i = 0; i < APM_MAC_SIZE-1; ++i) {
        mac[i] = strtoul(str_mac, &end, 16);
        if (*end != ':' || end - str_mac > 2)
           return 0;
        str_mac = end + 1;
    }

    mac[APM_MAC_SIZE-1] = strtoul(str_mac, &end, 16);
    if (*end != '\0' || end - str_mac > 2)
        return 0;
    return 1;
}

/*******************************************************************************
*  FUNC     :  取得应用程序的绝对路径
*  ARGS     :  p_relative_path    (应用程序名,带路径)
*           :  p_abs_dir          (获取应用程序的绝对路径)
*           :  ui_size            (p_abs_dir空间大小)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frget_absdir(char *p_relative_path, char *p_abs_dir, unsigned int ui_size)
{
    char *p_abs_path = NULL;
    char *p_tmp = NULL;
    unsigned int ui_dir_len = 0;
    char arr_path[PATH_MAX];
    memset(arr_path, 0x0, sizeof(arr_path));

    p_abs_path = realpath(p_relative_path, arr_path);
    if (p_abs_path == NULL)
    {
        return FR_FAIL;
    }

    /* 查询最后一个/后的字符串 */
    p_tmp = strrchr(p_abs_path, '/');
    /* 取得/之前字符 */
    ui_dir_len = p_tmp - p_abs_path;
    if (ui_dir_len >= ui_size)
    {
        return FR_FAIL;
    }
    strncpy(p_abs_dir, arr_path, ui_dir_len + 1);
    p_abs_dir[ui_dir_len] = '\0';

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  将struct timeval的时间转换为本地时间
*
*  ARGS     :  p_tv             （struct timeval结构体指针）
*           ：  p_time             将struct timeval的时间
*                                转换年/月/日  时:分:秒.微秒格式输出
*           :  ui_time_size      p_time的空间大小
*  RTN      :  FR_SUCC           (normal)
*              FR_FAIL           (error)
*  NOTE     :
*******************************************************************************/
int frtime2str(struct timeval *p_tv , char *p_time, unsigned int ui_time_size)
{
    struct tm *p_tm = NULL;

    if(p_tv == NULL || p_time == NULL || ui_time_size <= 1)
        return FR_FAIL;

    p_tm = localtime(&(p_tv->tv_sec));

    snprintf(p_time,ui_time_size,"%04d/%02d/%02d  %02d:%02d:%02d.%06d",
            p_tm->tm_year + 1900,p_tm->tm_mon + 1,p_tm->tm_mday,
            p_tm->tm_hour,p_tm->tm_min,p_tm->tm_sec,(int)p_tv->tv_usec);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  计算两个时间戳的差（以微秒显示）
*
*  ARGS     :  p_tv_pre          前一个时间戳
*           ：   p_tv_now          当前时间戳
*
*  RTN      :  time_diff         返回时间差( 当前时间戳 - 前一个时间戳)
*
*  NOTE     :
*******************************************************************************/
long frtime_diff(struct timeval *p_tv_pre, struct timeval *p_tv_now)
{
    return (p_tv_now->tv_sec - p_tv_pre->tv_sec)*1000000+ p_tv_now->tv_usec - p_tv_pre->tv_usec;
}


/*******************************************************************************
*  FUNC     :  用于没有数据结尾符的数据出力，使用log出力
*  ARGS     :  p_title    (出力数据抬头)
*           :  p_data     (数据)
*           :  ui_size    (数据长度)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frprint_bin(const char *p_fun, const char *p_file, unsigned int ui_line
               , const char *p_title, const char *p_data, unsigned int ui_size)
{
    char *p_buff=NULL;

    if(p_data == NULL || ui_size <= 0)
    {
        printf("%s no data", p_title);
        return;
    }

    p_buff = frmemdup(p_data, ui_size+1);
    if(p_buff == NULL)
    {
        printf("%s frmemdup err", p_title);
        return;
    }

    p_buff[ui_size] = '\0';
    printf("[%s(%s:%u)]%s[%s]", p_fun, p_file, ui_line, p_title, p_buff);
    frfree(p_buff);

    return;
}

/*******************************************************************************
*  FUNC     :  l4调试
*  ARGS     :  us_proto  (协议 tcp/udp)
*           :  ui_src    (原地址)
*           :  us_sport  (原端口)
*           :  ui_dest   (目的地址)
*           :  us_dport  (目的端口)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frprint_l4(const char *p_fun, const char *p_file, unsigned int ui_line
              , u_short ip_proto, u_int src_ip, u_short src_port, u_int dst_ip,u_short dst_port)
{
    char arr_buff[128];

    sprintf(arr_buff, "%s ", FR_L4PROTO2STR(ip_proto));
    strcat(arr_buff, int_ntoa (src_ip));
    sprintf(arr_buff + strlen (arr_buff), ":%i->", src_port);
    strcat(arr_buff, int_ntoa (dst_ip));
    sprintf(arr_buff + strlen (arr_buff), ":%i", dst_port);

    printf("[%s(%s:%u)]%s\n", p_fun, p_file, ui_line, arr_buff);
    return;
}

